package com.zeus.core.task;

import com.google.common.collect.Maps;
import com.zeus.common.log.ZeusLoggerConfig;
import com.zeus.core.report.ZeusReportClient;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 聚合任务
 *
 * @author f1ybear_wang  2022/2/24 5:40 下午
 */
public class GatherTask {
    private final static Logger log = LoggerFactory.getLogger(GatherTask.class);
    /**
     * 任务最大数量
     */
    private static final int TASK_MAX_SIZE = 1000;

    /**
     * 定时任务线程池
     */
    private static final ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,
        new BasicThreadFactory.Builder().namingPattern("zeus_gather_task_thread_%d").daemon(true).build());

    /**
     * 任务Map
     */
    private static final Map<String, ZeusReportClient> TASK_MAP = Maps.newConcurrentMap();

    /**
     * 是否已经初始化
     */
    private static volatile boolean inited;

    /**
     * 私有化，防止实例化
     *
     * @author f1ybear_wang  2022/2/24 5:43 下午
     */
    private GatherTask() {
        // default
    }

    public static void addTask(ZeusReportClient client) {
        String code = client.uniqueCode();
        if (code == null || client == null) {
            return;
        }
        ZeusReportClient oldClient = TASK_MAP.get(code);
        if (oldClient != null) {
            // 增加次数
            boolean flag = oldClient.addCount();
            if (flag) {
                return;
            }
            // 保存失败，说明已经完成，应该重新进行添加
        }
        // 新建
        TASK_MAP.put(code, client);
    }

    /**
     * 聚合任务初始化
     *
     * @author wangfeixiong126@gmail.com  2021/6/24 2:09 上午
     */
    public static void init() {
        try {
            if (inited) {
                return;
            }

            ScheduledFuture<?> scheduledFuture = executorService.scheduleAtFixedRate(() -> {
                try {
                    doTask();
                } catch (Throwable e) {
                    if (log.isWarnEnabled() && ZeusLoggerConfig.needEnableLogger()) {
                        log.warn("### Zeus报警服务, 聚合任务执行出现异常 >> errMsg = {}", e.getMessage());
                    }
                }
            }, 0, 15L, TimeUnit.SECONDS);

            // JVM关闭
            Runtime.getRuntime().addShutdownHook(new Thread(() -> {
                try {
                    scheduledFuture.cancel(true);
                    executorService.shutdown();
                } catch (Throwable throwable) {
                    if (log.isWarnEnabled() && ZeusLoggerConfig.needEnableLogger()) {
                        log.warn("### Zeus报警服务, 聚合任务关闭出现异常 >> errMsg = {}", throwable.getMessage());
                    }
                }
            }));

            inited = true;
            if (log.isInfoEnabled() && ZeusLoggerConfig.needEnableLogger()) {
                log.info(">>> 宙斯初始聚合任务完成");
            }
        } catch (Throwable e) {
            if (log.isWarnEnabled() && ZeusLoggerConfig.needEnableLogger()) {
                log.warn("### 宙斯初始聚合任务出现异常:", e);
            }
        }
    }

    /**
     * 执行聚合任务
     *
     * @author f1ybear_wang  2022/2/25 12:46 上午
     */
    private static void doTask() {

        if (TASK_MAP == null || TASK_MAP.isEmpty()) {
            return;
        }

        if (log.isInfoEnabled() && ZeusLoggerConfig.needEnableLogger()) {
            log.info(">>> Zeus报警服务, 开始执行聚合任务定时扫描 >> map.size = {}", TASK_MAP.size());
        }

        if (TASK_MAP.size() > TASK_MAX_SIZE) {
            if (log.isWarnEnabled() && ZeusLoggerConfig.needEnableLogger()) {
                log.warn("### Zeus报警服务, 聚合任务池中任务数量已超过最大限度1000, 开始自动销毁任务! >> map.size = {}", TASK_MAP.size());
            }
            TASK_MAP.clear();
            return;
        }
        for (Map.Entry<String, ZeusReportClient> entry : TASK_MAP.entrySet()) {
            ZeusReportClient client = entry.getValue();
            if (client == null) {
                continue;
            }

            // 继续执行任务
            client.complete();

            if (client.isCompleted()) {
                TASK_MAP.remove(entry.getKey());
                return;
            }
        }
    }

}
